﻿/***************************************************************************
    Copyright (c) Microsoft Corporation. All rights reserved.
    This code is licensed under the Visual Studio 
    Visualization and Modeling SDK license terms.

    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
***************************************************************************/

using System;
using System.Data.Objects.SqlClient;
using System.Linq;
namespace Microsoft.VisualStudio.ArchitectureTools.CodeRepositoryQuery
{
    /// <summary>
    /// Extension methods used to simplify the use of the query API
    /// </summary>
    public static class Extensions
    {
        /// <summary>
        /// Computes the Strong name of an assembly
        /// </summary>
        /// <param name="assembly">AssemblyInformation</param>
        /// <returns>Strong name for the assembly</returns>
        [Obsolete("This extension method is no longer necessary. Use the AssemblyName property instead")]
        public static string GetStrongName(this IAssembly assembly)
        {
            return string.Format("{0}, Version={1}.{2}.{3}.{4}, Culture={5}, PublicKeyToken={6}",
                assembly.Name, assembly.VersionMajor, assembly.VersionMinor, assembly.VersionBuild, assembly.VersionRevision, string.IsNullOrEmpty(assembly.Culture) ? "neutral" : assembly.Culture,
                         assembly.PublicKeyToken != null ? System.BitConverter.ToString(assembly.PublicKeyToken).Replace("-", string.Empty).ToLowerInvariant() : "null"
                         );
        }

        /// <summary>
        /// Get a query expression retrieving all the representations of a fully qualified type described by its assembly name and type name
        /// </summary>
        /// <param name="dbContext">Database context</param>
        /// <param name="namespaceName">Namespace</param>
        /// <param name="typeName">Name of the type</param>
        /// <returns>A query to get all the representations of the fully qualified named type, specified by namespace and type name</returns>
        public static IQueryable<Type> GetAllRepresentationsForFullyQualifiedType(this RepositoryEntities dbContext, string namespaceName, string typeName)
        {
            // TODO: need to add a notion of scope
            IQueryable<Type> fullyQualifiedTypes = dbContext.Types.Where(t => t.Hash_Name == SqlFunctions.Checksum(typeName) && t.Namespace.Hash_Name == SqlFunctions.Checksum(namespaceName)
                && t.Name == typeName && t.Namespace.Name == namespaceName);
            return fullyQualifiedTypes;
        }

        /// <summary>
        /// Get a query expression retrieving all the representations of a given type
        /// </summary>
        /// <param name="dbContext">Database context</param>
        /// <param name="type">Type to find</param>
        /// <returns>A query to get all the representations of a given type</returns>
        public static IQueryable<Type> GetAllRepresentationsForType(this RepositoryEntities dbContext, Type type)
        {
            int? hashTypeName = type.Hash_Name;
            int? hashNamespace = type.Namespace.Hash_Name;
            int? hashAssemblyName = type.IsReference ? type.Namespace.AssemblyReference.Hash_AssemblyName : type.ScopingAssembly.Hash_AssemblyName;


            IQueryable<Type> typeRepresentations = dbContext.Types.Where(t => t.Hash_Name == hashTypeName
                                                                           && t.Namespace.Hash_Name == hashNamespace
                                                                           && t.Namespace.Hash_Name == hashAssemblyName
                                                                           && t.Name == type.Name
                                                                           && t.Namespace.Name == type.Namespace.Name);
            return typeRepresentations;
        }

        /// <summary>
        /// Get a query expression retrieving all the representations of TypeDefinition of a fully qualified type described by its assembly name and type name
        /// </summary>
        /// <param name="dbContext">Database context</param>
        /// <param name="namespaceName">Namespace</param>
        /// <param name="typeName">Name of the type</param>
        /// <returns>A query to get all the representations of the fully qualified named type</returns>
        public static IQueryable<TypeDefinition> GetAllDefinitionsForFullyQualifiedType(this RepositoryEntities dbContext, string namespaceName, string typeName)
        {
            IQueryable<TypeDefinition> fullyQualifiedTypeDefinitions = GetAllRepresentationsForFullyQualifiedType(dbContext, namespaceName, typeName).Where(t => !t.IsReference).Select(t => t.TypeDefinition);
            return fullyQualifiedTypeDefinitions;
        }

    }
}
